﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Windows.Forms;

using Xeml.Document;
using Xeml.SQLDataProviders;

namespace Xid.Controls
{
    public partial class DataConnectionWizard : Form, INotifyPropertyChanged
    {

        private DataProviderConfiguration _editConfig;
        private String _editOriginalName; // configs are keyed on the name, so save this one in case the config's name gets edited
        private bool _loadAllConfigs; // only matters when editing one single config, to mark that we want to have access to all configs anyway

        private DataProviderResource _providerResource;
        public DataProviderResource ProviderResource
        {
            get { return _providerResource; }
            set { _providerResource = value; }
        }

        /// <summary>
        /// To signal that one of the configuration files has changed
        /// </summary>
        private bool _hasChanged = false;
        public void HasChanged(object o, PropertyChangedEventArgs e)
        {
            _hasChanged = true;
        }

        public DataConnectionWizard()
        {
            InitializeComponent();

            _loadAllConfigs = true;

            // Load in the possible DataDrivers
            Dictionary<string, string> NameUriDict = DataProviderManager.Instance.GetNameUriDict;
            if (NameUriDict.Count > 0) // make sure we have items, otherwise exception is thrown :/
            {
                cbDataDriver.DataSource = new BindingSource(NameUriDict, null);
                cbDataDriver.DisplayMember = "Key";
                cbDataDriver.ValueMember = "Value";
            }
        }

        /// <summary>
        /// Startup this dialog with only one configuration
        /// </summary>
        /// <param name="config">Only load this configuration</param>
        public DataConnectionWizard(DataProviderConfiguration config, bool loadAllConfigs = false)
        {
            InitializeComponent();

            _editConfig = config;
            _editOriginalName = config.Name; // save the name of the config to edit
            _loadAllConfigs = loadAllConfigs;

            // Load in the possible DataDrivers
            Dictionary<string, string> NameUriDict = loadAllConfigs ? 
                DataProviderManager.Instance.GetNameUriDict :
                DataProviderManager.Instance.GetNameUriDict.Where(x => x.Value == config.ProviderUri).ToDictionary(x => x.Key, x => x.Value);

            if (NameUriDict.Count > 0) // make sure we have items, otherwise exception is thrown :/
            {
                cbDataDriver.DataSource = new BindingSource(NameUriDict, null);
                cbDataDriver.DisplayMember = "Key";
                cbDataDriver.ValueMember = "Value";

                cbDataDriver.Text = DataProviderManager.Instance.GetNameUriDict.Where(x => x.Value == config.ProviderUri).Select(x => x.Key).FirstOrDefault();
                this.cbDataDriver_SelectionChangeCommitted(cbDataDriver, new EventArgs());
                this.cbDataConfiguration_SelectedIndexChanged(cbDataConfiguration, new EventArgs());
            }
        }

        private void cbDataDriver_SelectionChangeCommitted(object sender, EventArgs e)
        {
            ComboBox cb = (ComboBox)sender;

            Dictionary<String, DataProviderConfiguration> sqlconfigurations = new Dictionary<string,DataProviderConfiguration>();
            if (_editConfig != null && !_loadAllConfigs) //  only load the config we're editing
            {
                DataProviderConfiguration editConfigCopy = new DataProviderConfiguration(_editConfig);
                editConfigCopy.PropertyChanged += new PropertyChangedEventHandler(HasChanged);
                String name = _editConfig.Name != null ? _editConfig.Name : String.Empty;
                sqlconfigurations.Add(name, editConfigCopy);
            }
            else
            {
                // Load in the possible configuration settings
                String uri = ((KeyValuePair<string, string>)cb.SelectedItem).Value; // get the Uri

                // copy the DataConnectionConfigurations so that we could still cancel the changes
                foreach (KeyValuePair<string, DataProviderConfiguration> keyvalue in Xeml.SQLDataProviders.Configuration.GetDataProviderConfigurations(uri))
                {   
                    DataProviderConfiguration currentConfig = new DataProviderConfiguration(keyvalue.Value);
                    currentConfig.PropertyChanged += new PropertyChangedEventHandler(HasChanged);
                    sqlconfigurations.Add(keyvalue.Key, currentConfig);
                }
                sqlconfigurations.Add("Add new configuration ...", new DataProviderConfiguration(uri));
            }
            cbDataConfiguration.DataSource = new BindingSource(sqlconfigurations, null);
            cbDataConfiguration.DisplayMember = "Key";
            cbDataConfiguration.ValueMember = "Value";

            if (_editConfig != null)
            {
                cbDataConfiguration.Text = _editConfig.Name;
            }
        }

        private void cbDataConfiguration_SelectedIndexChanged(object sender, EventArgs e)
        {   
            ComboBox cb = (ComboBox)sender;
            if (cb.SelectedIndex != -1)
            {
                var item = (KeyValuePair<String, DataProviderConfiguration>)cb.SelectedItem;
                DataProviderConfiguration dpc = (DataProviderConfiguration)(item).Value;
                pgConfiguration.SelectedObject = dpc;
            }
            else
            {
                cb.SelectedIndex = 0;
            }
        }

        private void btnOk_Click(object sender, EventArgs e)
        {
            DataProviderConfiguration dpConfig = (DataProviderConfiguration)pgConfiguration.SelectedObject;
            if (dpConfig.Name == String.Empty)
            {
                MessageBox.Show(this, "No name given!", "Unable to save configuration!");
                this.DialogResult = DialogResult.None; // cancel the click event
            }
            else
            {
                // save the configuration locally
                if (_editConfig != null)
                {
                    Xeml.SQLDataProviders.Configuration.UpdateConfiguration(dpConfig, _editOriginalName, dpConfig.Name);
                    if (_providerResource.Provider.Configuration == null)
                    {
                        _providerResource.LoadConfiguredComponent(dpConfig.Name);
                    }
                    else
                    {
                        _providerResource.Provider.Configure(dpConfig);
                    }
                    _providerResource.FriendlyName = dpConfig.Name;
                }
                else
                {
                    Xeml.SQLDataProviders.Configuration.SaveConfigurations(
                        cbDataConfiguration.Items.OfType<KeyValuePair<string, DataProviderConfiguration>>().
                        Select(x => x.Value).ToList<DataProviderConfiguration>()
                    );

                    _providerResource = new DataProviderResource();
                    _providerResource.LoadConfiguredComponent(dpConfig.Name);
                	_providerResource.FriendlyName = dpConfig.Name;
                }


                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("Configuration"));
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}